| Conditions | 1 |
| Paths | 64 |
| Total Lines | 296 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | /* |
||
| 25 | })(function (loadImage) { |
||
| 26 | 'use strict' |
||
| 27 | |||
| 28 | loadImage.ExifMap = function () { |
||
| 29 | return this |
||
| 30 | } |
||
| 31 | |||
| 32 | loadImage.ExifMap.prototype.map = { |
||
| 33 | Orientation: 0x0112 |
||
| 34 | } |
||
| 35 | |||
| 36 | loadImage.ExifMap.prototype.get = function (id) { |
||
| 37 | return this[id] || this[this.map[id]] |
||
| 38 | } |
||
| 39 | |||
| 40 | loadImage.getExifThumbnail = function (dataView, offset, length) { |
||
| 41 | if (!length || offset + length > dataView.byteLength) { |
||
| 42 | console.log('Invalid Exif data: Invalid thumbnail data.') |
||
|
|
|||
| 43 | return |
||
| 44 | } |
||
| 45 | return loadImage.createObjectURL( |
||
| 46 | new Blob([dataView.buffer.slice(offset, offset + length)]) |
||
| 47 | ) |
||
| 48 | } |
||
| 49 | |||
| 50 | loadImage.exifTagTypes = { |
||
| 51 | // byte, 8-bit unsigned int: |
||
| 52 | 1: { |
||
| 53 | getValue: function (dataView, dataOffset) { |
||
| 54 | return dataView.getUint8(dataOffset) |
||
| 55 | }, |
||
| 56 | size: 1 |
||
| 57 | }, |
||
| 58 | // ascii, 8-bit byte: |
||
| 59 | 2: { |
||
| 60 | getValue: function (dataView, dataOffset) { |
||
| 61 | return String.fromCharCode(dataView.getUint8(dataOffset)) |
||
| 62 | }, |
||
| 63 | size: 1, |
||
| 64 | ascii: true |
||
| 65 | }, |
||
| 66 | // short, 16 bit int: |
||
| 67 | 3: { |
||
| 68 | getValue: function (dataView, dataOffset, littleEndian) { |
||
| 69 | return dataView.getUint16(dataOffset, littleEndian) |
||
| 70 | }, |
||
| 71 | size: 2 |
||
| 72 | }, |
||
| 73 | // long, 32 bit int: |
||
| 74 | 4: { |
||
| 75 | getValue: function (dataView, dataOffset, littleEndian) { |
||
| 76 | return dataView.getUint32(dataOffset, littleEndian) |
||
| 77 | }, |
||
| 78 | size: 4 |
||
| 79 | }, |
||
| 80 | // rational = two long values, first is numerator, second is denominator: |
||
| 81 | 5: { |
||
| 82 | getValue: function (dataView, dataOffset, littleEndian) { |
||
| 83 | return ( |
||
| 84 | dataView.getUint32(dataOffset, littleEndian) / |
||
| 85 | dataView.getUint32(dataOffset + 4, littleEndian) |
||
| 86 | ) |
||
| 87 | }, |
||
| 88 | size: 8 |
||
| 89 | }, |
||
| 90 | // slong, 32 bit signed int: |
||
| 91 | 9: { |
||
| 92 | getValue: function (dataView, dataOffset, littleEndian) { |
||
| 93 | return dataView.getInt32(dataOffset, littleEndian) |
||
| 94 | }, |
||
| 95 | size: 4 |
||
| 96 | }, |
||
| 97 | // srational, two slongs, first is numerator, second is denominator: |
||
| 98 | 10: { |
||
| 99 | getValue: function (dataView, dataOffset, littleEndian) { |
||
| 100 | return ( |
||
| 101 | dataView.getInt32(dataOffset, littleEndian) / |
||
| 102 | dataView.getInt32(dataOffset + 4, littleEndian) |
||
| 103 | ) |
||
| 104 | }, |
||
| 105 | size: 8 |
||
| 106 | } |
||
| 107 | } |
||
| 108 | // undefined, 8-bit byte, value depending on field: |
||
| 109 | loadImage.exifTagTypes[7] = loadImage.exifTagTypes[1] |
||
| 110 | |||
| 111 | loadImage.getExifValue = function ( |
||
| 112 | dataView, |
||
| 113 | tiffOffset, |
||
| 114 | offset, |
||
| 115 | type, |
||
| 116 | length, |
||
| 117 | littleEndian |
||
| 118 | ) { |
||
| 119 | var tagType = loadImage.exifTagTypes[type] |
||
| 120 | var tagSize |
||
| 121 | var dataOffset |
||
| 122 | var values |
||
| 123 | var i |
||
| 124 | var str |
||
| 125 | var c |
||
| 126 | if (!tagType) { |
||
| 127 | console.log('Invalid Exif data: Invalid tag type.') |
||
| 128 | return |
||
| 129 | } |
||
| 130 | tagSize = tagType.size * length |
||
| 131 | // Determine if the value is contained in the dataOffset bytes, |
||
| 132 | // or if the value at the dataOffset is a pointer to the actual data: |
||
| 133 | dataOffset = |
||
| 134 | tagSize > 4 |
||
| 135 | ? tiffOffset + dataView.getUint32(offset + 8, littleEndian) |
||
| 136 | : offset + 8 |
||
| 137 | if (dataOffset + tagSize > dataView.byteLength) { |
||
| 138 | console.log('Invalid Exif data: Invalid data offset.') |
||
| 139 | return |
||
| 140 | } |
||
| 141 | if (length === 1) { |
||
| 142 | return tagType.getValue(dataView, dataOffset, littleEndian) |
||
| 143 | } |
||
| 144 | values = [] |
||
| 145 | for (i = 0; i < length; i += 1) { |
||
| 146 | values[i] = tagType.getValue( |
||
| 147 | dataView, |
||
| 148 | dataOffset + i * tagType.size, |
||
| 149 | littleEndian |
||
| 150 | ) |
||
| 151 | } |
||
| 152 | if (tagType.ascii) { |
||
| 153 | str = '' |
||
| 154 | // Concatenate the chars: |
||
| 155 | for (i = 0; i < values.length; i += 1) { |
||
| 156 | c = values[i] |
||
| 157 | // Ignore the terminating NULL byte(s): |
||
| 158 | if (c === '\u0000') { |
||
| 159 | break |
||
| 160 | } |
||
| 161 | str += c |
||
| 162 | } |
||
| 163 | return str |
||
| 164 | } |
||
| 165 | return values |
||
| 166 | } |
||
| 167 | |||
| 168 | loadImage.parseExifTag = function ( |
||
| 169 | dataView, |
||
| 170 | tiffOffset, |
||
| 171 | offset, |
||
| 172 | littleEndian, |
||
| 173 | data |
||
| 174 | ) { |
||
| 175 | var tag = dataView.getUint16(offset, littleEndian) |
||
| 176 | data.exif[tag] = loadImage.getExifValue( |
||
| 177 | dataView, |
||
| 178 | tiffOffset, |
||
| 179 | offset, |
||
| 180 | dataView.getUint16(offset + 2, littleEndian), // tag type |
||
| 181 | dataView.getUint32(offset + 4, littleEndian), // tag length |
||
| 182 | littleEndian |
||
| 183 | ) |
||
| 184 | } |
||
| 185 | |||
| 186 | loadImage.parseExifTags = function ( |
||
| 187 | dataView, |
||
| 188 | tiffOffset, |
||
| 189 | dirOffset, |
||
| 190 | littleEndian, |
||
| 191 | data |
||
| 192 | ) { |
||
| 193 | var tagsNumber, dirEndOffset, i |
||
| 194 | if (dirOffset + 6 > dataView.byteLength) { |
||
| 195 | console.log('Invalid Exif data: Invalid directory offset.') |
||
| 196 | return |
||
| 197 | } |
||
| 198 | tagsNumber = dataView.getUint16(dirOffset, littleEndian) |
||
| 199 | dirEndOffset = dirOffset + 2 + 12 * tagsNumber |
||
| 200 | if (dirEndOffset + 4 > dataView.byteLength) { |
||
| 201 | console.log('Invalid Exif data: Invalid directory size.') |
||
| 202 | return |
||
| 203 | } |
||
| 204 | for (i = 0; i < tagsNumber; i += 1) { |
||
| 205 | this.parseExifTag( |
||
| 206 | dataView, |
||
| 207 | tiffOffset, |
||
| 208 | dirOffset + 2 + 12 * i, // tag offset |
||
| 209 | littleEndian, |
||
| 210 | data |
||
| 211 | ) |
||
| 212 | } |
||
| 213 | // Return the offset to the next directory: |
||
| 214 | return dataView.getUint32(dirEndOffset, littleEndian) |
||
| 215 | } |
||
| 216 | |||
| 217 | loadImage.parseExifData = function (dataView, offset, length, data, options) { |
||
| 218 | if (options.disableExif) { |
||
| 219 | return |
||
| 220 | } |
||
| 221 | var tiffOffset = offset + 10 |
||
| 222 | var littleEndian |
||
| 223 | var dirOffset |
||
| 224 | var thumbnailData |
||
| 225 | // Check for the ASCII code for "Exif" (0x45786966): |
||
| 226 | if (dataView.getUint32(offset + 4) !== 0x45786966) { |
||
| 227 | // No Exif data, might be XMP data instead |
||
| 228 | return |
||
| 229 | } |
||
| 230 | if (tiffOffset + 8 > dataView.byteLength) { |
||
| 231 | console.log('Invalid Exif data: Invalid segment size.') |
||
| 232 | return |
||
| 233 | } |
||
| 234 | // Check for the two null bytes: |
||
| 235 | if (dataView.getUint16(offset + 8) !== 0x0000) { |
||
| 236 | console.log('Invalid Exif data: Missing byte alignment offset.') |
||
| 237 | return |
||
| 238 | } |
||
| 239 | // Check the byte alignment: |
||
| 240 | switch (dataView.getUint16(tiffOffset)) { |
||
| 241 | case 0x4949: |
||
| 242 | littleEndian = true |
||
| 243 | break |
||
| 244 | case 0x4d4d: |
||
| 245 | littleEndian = false |
||
| 246 | break |
||
| 247 | default: |
||
| 248 | console.log('Invalid Exif data: Invalid byte alignment marker.') |
||
| 249 | return |
||
| 250 | } |
||
| 251 | // Check for the TIFF tag marker (0x002A): |
||
| 252 | if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002a) { |
||
| 253 | console.log('Invalid Exif data: Missing TIFF marker.') |
||
| 254 | return |
||
| 255 | } |
||
| 256 | // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal: |
||
| 257 | dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian) |
||
| 258 | // Create the exif object to store the tags: |
||
| 259 | data.exif = new loadImage.ExifMap() |
||
| 260 | // Parse the tags of the main image directory and retrieve the |
||
| 261 | // offset to the next directory, usually the thumbnail directory: |
||
| 262 | dirOffset = loadImage.parseExifTags( |
||
| 263 | dataView, |
||
| 264 | tiffOffset, |
||
| 265 | tiffOffset + dirOffset, |
||
| 266 | littleEndian, |
||
| 267 | data |
||
| 268 | ) |
||
| 269 | if (dirOffset && !options.disableExifThumbnail) { |
||
| 270 | thumbnailData = { exif: {} } |
||
| 271 | dirOffset = loadImage.parseExifTags( |
||
| 272 | dataView, |
||
| 273 | tiffOffset, |
||
| 274 | tiffOffset + dirOffset, |
||
| 275 | littleEndian, |
||
| 276 | thumbnailData |
||
| 277 | ) |
||
| 278 | // Check for JPEG Thumbnail offset: |
||
| 279 | if (thumbnailData.exif[0x0201]) { |
||
| 280 | data.exif.Thumbnail = loadImage.getExifThumbnail( |
||
| 281 | dataView, |
||
| 282 | tiffOffset + thumbnailData.exif[0x0201], |
||
| 283 | thumbnailData.exif[0x0202] // Thumbnail data length |
||
| 284 | ) |
||
| 285 | } |
||
| 286 | } |
||
| 287 | // Check for Exif Sub IFD Pointer: |
||
| 288 | if (data.exif[0x8769] && !options.disableExifSub) { |
||
| 289 | loadImage.parseExifTags( |
||
| 290 | dataView, |
||
| 291 | tiffOffset, |
||
| 292 | tiffOffset + data.exif[0x8769], // directory offset |
||
| 293 | littleEndian, |
||
| 294 | data |
||
| 295 | ) |
||
| 296 | } |
||
| 297 | // Check for GPS Info IFD Pointer: |
||
| 298 | if (data.exif[0x8825] && !options.disableExifGps) { |
||
| 299 | loadImage.parseExifTags( |
||
| 300 | dataView, |
||
| 301 | tiffOffset, |
||
| 302 | tiffOffset + data.exif[0x8825], // directory offset |
||
| 303 | littleEndian, |
||
| 304 | data |
||
| 305 | ) |
||
| 306 | } |
||
| 307 | } |
||
| 308 | |||
| 309 | // Registers the Exif parser for the APP1 JPEG meta data segment: |
||
| 310 | loadImage.metaDataParsers.jpeg[0xffe1].push(loadImage.parseExifData) |
||
| 311 | |||
| 312 | // Adds the following properties to the parseMetaData callback data: |
||
| 313 | // * exif: The exif tags, parsed by the parseExifData method |
||
| 314 | |||
| 315 | // Adds the following options to the parseMetaData method: |
||
| 316 | // * disableExif: Disables Exif parsing. |
||
| 317 | // * disableExifThumbnail: Disables parsing of the Exif Thumbnail. |
||
| 318 | // * disableExifSub: Disables parsing of the Exif Sub IFD. |
||
| 319 | // * disableExifGps: Disables parsing of the Exif GPS Info IFD. |
||
| 320 | }) |
||
| 321 |